home *** CD-ROM | disk | FTP | other *** search
/ Enter 2006 September / Enter 09 2006.iso / Internet / SpamExperts Home 1.1 / SpamExperts Home.exe / lib / spamexperts.modules / dns / query.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2006-07-14  |  11.2 KB  |  367 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.4)
  3.  
  4. '''Talk to a DNS server.'''
  5. from __future__ import generators
  6. import errno
  7. import select
  8. import socket
  9. import struct
  10. import sys
  11. import time
  12. import dns.exception as dns
  13. import dns.inet as dns
  14. import dns.name as dns
  15. import dns.message as dns
  16. import dns.rdataclass as dns
  17. import dns.rdatatype as dns
  18.  
  19. class UnexpectedSource(dns.exception.DNSException):
  20.     '''Raised if a query response comes from an unexpected address or port.'''
  21.     pass
  22.  
  23.  
  24. class BadResponse(dns.exception.FormError):
  25.     '''Raised if a query response does not respond to the question asked.'''
  26.     pass
  27.  
  28.  
  29. def _compute_expiration(timeout):
  30.     if timeout is None:
  31.         return None
  32.     else:
  33.         return time.time() + timeout
  34.  
  35.  
  36. def _wait_for(ir, iw, ix, expiration):
  37.     if expiration is None:
  38.         timeout = None
  39.     else:
  40.         timeout = expiration - time.time()
  41.         if timeout <= 0.0:
  42.             raise dns.exception.Timeout
  43.         
  44.     if timeout is None:
  45.         (r, w, x) = select.select(ir, iw, ix)
  46.     else:
  47.         (r, w, x) = select.select(ir, iw, ix, timeout)
  48.     if len(r) == 0 and len(w) == 0 and len(x) == 0:
  49.         raise dns.exception.Timeout
  50.     
  51.  
  52.  
  53. def _wait_for_readable(s, expiration):
  54.     _wait_for([
  55.         s], [], [
  56.         s], expiration)
  57.  
  58.  
  59. def _wait_for_writable(s, expiration):
  60.     _wait_for([], [
  61.         s], [
  62.         s], expiration)
  63.  
  64.  
  65. def udp(q, where, timeout = None, port = 53, af = None, source = None, source_port = 0):
  66.     '''Return the response obtained after sending a query via UDP.
  67.  
  68.     @param q: the query
  69.     @type q: dns.message.Message
  70.     @param where: where to send the message
  71.     @type where: string containing an IPv4 or IPv6 address
  72.     @param timeout: The number of seconds to wait before the query times out.
  73.     If None, the default, wait forever.
  74.     @type timeout: float
  75.     @param port: The port to which to send the message.  The default is 53.
  76.     @type port: int
  77.     @param af: the address family to use.  The default is None, which
  78.     causes the address family to use to be inferred from the form of of where.
  79.     If the inference attempt fails, AF_INET is used.
  80.     @type af: int
  81.     @rtype: dns.message.Message object
  82.     @param source: source address.  The default is the IPv4 wildcard address.
  83.     @type source: string
  84.     @param source_port: The port from which to send the message.
  85.     The default is 0.
  86.     @type source_port: int'''
  87.     wire = q.to_wire()
  88.     if af is None:
  89.         
  90.         try:
  91.             af = dns.inet.af_for_address(where)
  92.         af = dns.inet.AF_INET
  93.  
  94.     
  95.     if af == dns.inet.AF_INET:
  96.         destination = (where, port)
  97.         if source is not None:
  98.             source = (source, source_port)
  99.         
  100.     elif af == dns.inet.AF_INET6:
  101.         destination = (where, port, 0, 0)
  102.         if source is not None:
  103.             source = (source, source_port, 0, 0)
  104.         
  105.     
  106.     s = socket.socket(af, socket.SOCK_DGRAM, 0)
  107.     
  108.     try:
  109.         expiration = _compute_expiration(timeout)
  110.         s.setblocking(0)
  111.         if source is not None:
  112.             s.bind(source)
  113.         
  114.         _wait_for_writable(s, expiration)
  115.         s.sendto(wire, destination)
  116.         _wait_for_readable(s, expiration)
  117.         (wire, from_address) = s.recvfrom(65535)
  118.     finally:
  119.         s.close()
  120.  
  121.     if from_address != destination:
  122.         raise UnexpectedSource
  123.     
  124.     r = dns.message.from_wire(wire, keyring = q.keyring, request_mac = q.mac)
  125.     if not q.is_response(r):
  126.         raise BadResponse
  127.     
  128.     return r
  129.  
  130.  
  131. def _net_read(sock, count, expiration):
  132.     '''Read the specified number of bytes from sock.  Keep trying until we
  133.     either get the desired amount, or we hit EOF.
  134.     A Timeout exception will be raised if the operation is not completed
  135.     by the expiration time.
  136.     '''
  137.     s = ''
  138.     while count > 0:
  139.         _wait_for_readable(sock, expiration)
  140.         n = sock.recv(count)
  141.         if n == '':
  142.             raise EOFError
  143.         
  144.         count = count - len(n)
  145.         s = s + n
  146.     return s
  147.  
  148.  
  149. def _net_write(sock, data, expiration):
  150.     '''Write the specified data to the socket.
  151.     A Timeout exception will be raised if the operation is not completed
  152.     by the expiration time.
  153.     '''
  154.     current = 0
  155.     l = len(data)
  156.     while current < l:
  157.         _wait_for_writable(sock, expiration)
  158.         current += sock.send(data[current:])
  159.  
  160.  
  161. def _connect(s, address):
  162.     
  163.     try:
  164.         s.connect(address)
  165.     except socket.error:
  166.         (ty, v) = sys.exc_info()[:2]
  167.         if v[0] != errno.EINPROGRESS and v[0] != errno.EWOULDBLOCK and v[0] != errno.EALREADY:
  168.             raise ty, v
  169.         
  170.     except:
  171.         v[0] != errno.EALREADY
  172.  
  173.  
  174.  
  175. def tcp(q, where, timeout = None, port = 53, af = None, source = None, source_port = 0):
  176.     '''Return the response obtained after sending a query via TCP.
  177.  
  178.     @param q: the query
  179.     @type q: dns.message.Message object
  180.     @param where: where to send the message
  181.     @type where: string containing an IPv4 or IPv6 address
  182.     @param timeout: The number of seconds to wait before the query times out.
  183.     If None, the default, wait forever.
  184.     @type timeout: float
  185.     @param port: The port to which to send the message.  The default is 53.
  186.     @type port: int
  187.     @param af: the address family to use.  The default is None, which
  188.     causes the address family to use to be inferred from the form of of where.
  189.     If the inference attempt fails, AF_INET is used.
  190.     @type af: int
  191.     @rtype: dns.message.Message object
  192.     @param source: source address.  The default is the IPv4 wildcard address.
  193.     @type source: string
  194.     @param source_port: The port from which to send the message.
  195.     The default is 0.
  196.     @type source_port: int'''
  197.     wire = q.to_wire()
  198.     if af is None:
  199.         
  200.         try:
  201.             af = dns.inet.af_for_address(where)
  202.         af = dns.inet.AF_INET
  203.  
  204.     
  205.     if af == dns.inet.AF_INET:
  206.         destination = (where, port)
  207.         if source is not None:
  208.             source = (source, source_port)
  209.         
  210.     elif af == dns.inet.AF_INET6:
  211.         destination = (where, port, 0, 0)
  212.         if source is not None:
  213.             source = (source, source_port, 0, 0)
  214.         
  215.     
  216.     s = socket.socket(af, socket.SOCK_STREAM, 0)
  217.     
  218.     try:
  219.         expiration = _compute_expiration(timeout)
  220.         s.setblocking(0)
  221.         if source is not None:
  222.             s.bind(source)
  223.         
  224.         _connect(s, destination)
  225.         l = len(wire)
  226.         tcpmsg = struct.pack('!H', l) + wire
  227.         _net_write(s, tcpmsg, expiration)
  228.         ldata = _net_read(s, 2, expiration)
  229.         (l,) = struct.unpack('!H', ldata)
  230.         wire = _net_read(s, l, expiration)
  231.     finally:
  232.         s.close()
  233.  
  234.     r = dns.message.from_wire(wire, keyring = q.keyring, request_mac = q.mac)
  235.     if not q.is_response(r):
  236.         raise BadResponse
  237.     
  238.     return r
  239.  
  240.  
  241. def xfr(where, zone, rdtype = dns.rdatatype.AXFR, rdclass = dns.rdataclass.IN, timeout = None, port = 53, keyring = None, keyname = None, relativize = True, af = None, lifetime = None, source = None, source_port = 0):
  242.     '''Return a generator for the responses to a zone transfer.
  243.  
  244.     @param where: where to send the message
  245.     @type where: string containing an IPv4 or IPv6 address
  246.     @param zone: The name of the zone to transfer
  247.     @type zone: dns.name.Name object or string
  248.     @param rdtype: The type of zone transfer.  The default is
  249.     dns.rdatatype.AXFR.
  250.     @type rdtype: int or string
  251.     @param rdclass: The class of the zone transfer.  The default is
  252.     dns.rdatatype.IN.
  253.     @type rdclass: int or string
  254.     @param timeout: The number of seconds to wait for each response message.
  255.     If None, the default, wait forever.
  256.     @type timeout: float
  257.     @param port: The port to which to send the message.  The default is 53.
  258.     @type port: int
  259.     @param keyring: The TSIG keyring to use
  260.     @type keyring: dict
  261.     @param keyname: The name of the TSIG key to use
  262.     @type keyname: dns.name.Name object or string
  263.     @param relativize: If True, all names in the zone will be relativized to
  264.     the zone origin.  It is essential that the relativize setting matches
  265.     the one specified to dns.zone.from_xfr().
  266.     @type relativize: bool
  267.     @param af: the address family to use.  The default is None, which
  268.     causes the address family to use to be inferred from the form of of where.
  269.     If the inference attempt fails, AF_INET is used.
  270.     @type af: int
  271.     @param lifetime: The total number of seconds to spend doing the transfer.
  272.     If None, the default, then there is no limit on the time the transfer may
  273.     take.
  274.     @type lifetime: float
  275.     @rtype: generator of dns.message.Message objects.
  276.     @param source: source address.  The default is the IPv4 wildcard address.
  277.     @type source: string
  278.     @param source_port: The port from which to send the message.
  279.     The default is 0.
  280.     @type source_port: int'''
  281.     if isinstance(zone, str):
  282.         zone = dns.name.from_text(zone)
  283.     
  284.     q = dns.message.make_query(zone, rdtype, rdclass)
  285.     if keyring is not None:
  286.         q.use_tsig(keyring, keyname)
  287.     
  288.     wire = q.to_wire()
  289.     if af is None:
  290.         
  291.         try:
  292.             af = dns.inet.af_for_address(where)
  293.         af = dns.inet.AF_INET
  294.  
  295.     
  296.     if af == dns.inet.AF_INET:
  297.         destination = (where, port)
  298.         if source is not None:
  299.             source = (source, source_port)
  300.         
  301.     elif af == dns.inet.AF_INET6:
  302.         destination = (where, port, 0, 0)
  303.         if source is not None:
  304.             source = (source, source_port, 0, 0)
  305.         
  306.     
  307.     s = socket.socket(af, socket.SOCK_STREAM, 0)
  308.     if source is not None:
  309.         s.bind(source)
  310.     
  311.     expiration = _compute_expiration(lifetime)
  312.     _connect(s, destination)
  313.     l = len(wire)
  314.     tcpmsg = struct.pack('!H', l) + wire
  315.     _net_write(s, tcpmsg, expiration)
  316.     done = False
  317.     seen_soa = False
  318.     if relativize:
  319.         origin = zone
  320.         oname = dns.name.empty
  321.     else:
  322.         origin = None
  323.         oname = zone
  324.     tsig_ctx = None
  325.     first = True
  326.     while not done:
  327.         mexpiration = _compute_expiration(timeout)
  328.         if mexpiration is None or mexpiration > expiration:
  329.             mexpiration = expiration
  330.         
  331.         ldata = _net_read(s, 2, mexpiration)
  332.         (l,) = struct.unpack('!H', ldata)
  333.         wire = _net_read(s, l, mexpiration)
  334.         r = dns.message.from_wire(wire, keyring = q.keyring, request_mac = q.mac, xfr = True, origin = origin, tsig_ctx = tsig_ctx, multi = True, first = first)
  335.         tsig_ctx = r.tsig_ctx
  336.         first = False
  337.         if not seen_soa:
  338.             if not (r.answer) or r.answer[0].name != oname:
  339.                 raise dns.exception.FormError
  340.             
  341.             rrset = r.answer[0]
  342.             if rrset.rdtype != dns.rdatatype.SOA:
  343.                 raise dns.exception.FormError
  344.             
  345.             seen_soa = True
  346.             if len(r.answer) > 1 and r.answer[-1].name == oname:
  347.                 rrset = r.answer[-1]
  348.                 if rrset.rdtype == dns.rdatatype.SOA:
  349.                     if q.keyring and not (r.had_tsig):
  350.                         raise dns.exception.FormError, 'missing TSIG'
  351.                     
  352.                     done = True
  353.                 
  354.             
  355.         elif r.answer and r.answer[-1].name == oname:
  356.             rrset = r.answer[-1]
  357.             if rrset.rdtype == dns.rdatatype.SOA:
  358.                 if q.keyring and not (r.had_tsig):
  359.                     raise dns.exception.FormError, 'missing TSIG'
  360.                 
  361.                 done = True
  362.             
  363.         
  364.         yield r
  365.     s.close()
  366.  
  367.